package com.yf.framework.utils.excel;

import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.hutool.poi.excel.StyleSet;
import com.yf.framework.utils.excel.annotation.ExcelField;
import com.yf.framework.utils.reflect.Reflections;
import com.yf.framework.aspect.dict.DictDataGetter;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.*;

/**
 * excel导出工具类
 * @author bool
 */
@Component
public class ExportExcel {

    @Autowired
    private DictDataGetter baseDictService;

    /**
     * 导出数据
     * @param response
     * @param clazz 数据类型
     * @param title 表头名称
     * @param list 列表数据
     */
    public void export(HttpServletResponse response, Class clazz, String title, List list){

        // 获取当前类字段
        Field[] fields = clazz.getDeclaredFields();

        // 字段列表
        List<Field> fieldList = new ArrayList<>();

        for (Field field : fields) {
            if (!field.isAccessible()) {
                // 关闭反射访问安全检查，为了提高速度
                field.setAccessible(true);
            }

            // 只导出有注解的字段
            boolean export = field.isAnnotationPresent(ExcelField.class);
            if(!export){
                continue;
            }

            // 加入列表
            fieldList.add(field);
        }


        // 进行列排序
        Collections.sort(fieldList, (o1, o2) -> {
            ExcelField a1 = o1.getAnnotation(ExcelField.class);
            ExcelField a2 = o2.getAnnotation(ExcelField.class);
            return a1.sort() - a2.sort();
        });

        try {
            this.write(response, fieldList, title, list);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    /**
     * 导出数据
     * @param response
     * @param list
     * @throws Exception
     */
    private void write(HttpServletResponse response, List<Field> fieldList, String title, List list) throws IOException {

        ExcelWriter writer= ExcelUtil.getBigWriter();

        // 处理内容
        List<Map<String,Object>> rows = this.processRows(fieldList, list);

        writer.merge(rows.get(0).size() - 1, title);
        writer.write(rows, true);

        // 自适应宽度
        SXSSFSheet sheet = (SXSSFSheet) writer.getSheet();
        sheet.trackAllColumnsForAutoSizing();
        writer.autoSizeColumnAll();

        // 修整宽度
        this.setSizeColumn(writer.getSheet(), rows.size()-1);

        // 追加样式
        StyleSet styleSet = writer.getStyleSet();
        styleSet.setWrapText();
        styleSet.setAlign(HorizontalAlignment.LEFT, VerticalAlignment.CENTER);
        // styleSet.setBackgroundColor(IndexedColors.WHITE, true);

        CellStyle cellStyle = styleSet.getHeadCellStyle();
        cellStyle.setAlignment(HorizontalAlignment.CENTER);


        ServletOutputStream out = response.getOutputStream();
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        writer.flush(out, true);
        writer.close();
        IoUtil.close(out);
    }


    /**
     * 添加数据（通过annotation.ExportField添加数据）
     * @return list 数据列表
     */
    public List<Map<String,Object>> processRows(List<Field> fieldList, List list){

        List<Map<String,Object>> all = new ArrayList<>();
        for(Object data: list){
            Map<String, Object> row = new LinkedHashMap<>();
            for(Field field: fieldList){
                ExcelField ann = field.getAnnotation(ExcelField.class);
                Object val = Reflections.invokeGetter(data, field.getName());

                // 转换数据字典
                val = this.transDict(ann, val);

                // 转换常量
                val = this.transFilter(ann, val);

                // null显示为空字符
                if(val == null){
                    val = "";
                }

                // 统一转成文本处理
                row.put(ann.title(), String.valueOf(val));
            }
            all.add(row);
        }
        return all;
    }

    /**
     * 数据字典转换
     * @param ann
     * @param val
     * @return
     */
    private Object transDict(ExcelField ann, Object val){

        // 不需要处理
        if(StringUtils.isEmpty(ann.dictCode())){
            return val;
        }

        // 转换数据字典
        return  baseDictService.findDictText(ann.dictCode(), String.valueOf(val));
    }

    /**
     * 数据过滤转换
     * @param ann
     * @param val
     * @return
     */
    private Object transFilter(ExcelField ann, Object val){

        String filter = ann.filter();

        // 不需要处理
        if(StringUtils.isEmpty(filter)){
            return val;
        }

        String [] arr = filter.split(",");

        if(arr.length == 0){
            return val;
        }

        for(String item: arr){
            String [] arr1 = item.split("=");

            // 空用null表示
            if(((val==null || "".equals(String.valueOf(val))) && "null".equals(arr1[0])) || String.valueOf(val).equals(arr1[0])){
                return arr1[1];
            }
        }

        // 进行转换
        return val;
    }


    /**
     * 自适应宽度(中文支持)
     * @param sheet
     * @param size 因为for循环从0开始，size值为 列数-1
     */
    public void setSizeColumn(Sheet sheet, int size) {

        for (int i = 0; i <= size; i++) {
            int width = sheet.getColumnWidth(i)*2;
            if(width<255*256){
                sheet.setColumnWidth(i, width < 3000 ? 3000 : width);
            }
        }
    }


}
